package com.taldh.mutlithread;

import java.io.Serializable;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.AbstractQueuedSynchronizer;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;

/**
 * 设计一个工具：在同一时刻，只能两个线程被阻塞
 */
public class TwinsLock implements Lock, Serializable {

    private final Sync sync;

    public TwinsLock() {
        this.sync = new Sync();
    }

    @Override
    public void lock() {
        this.sync.acquireShared(1);
    }

    @Override
    public void lockInterruptibly() throws InterruptedException {
        this.sync.acquireSharedInterruptibly(1);
    }

    @Override
    public boolean tryLock() {
        return this.sync.tryAcquireShared(1) >= 0;
    }

    @Override
    public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
        return this.sync.tryAcquireSharedNanos(1, unit.toNanos(time));
    }

    @Override
    public void unlock() {
        this.sync.releaseShared(1);
    }

    @Override
    public Condition newCondition() {
        return sync.newCondition();
    }

    private class Sync extends AbstractQueuedSynchronizer {
        public Sync() {
            setState(2);
        }

        @Override
        protected int tryAcquireShared(int arg) {
            for (;;) { // 一般cas是需要和自旋结合使用。
                int state = getState();
                if (state <= 0) {
                    return -1; // 这里返回-1而不是使用continue，是想让这个线程进入队列，进入队列之后轮到它的时候自然会有线程唤醒它然后再次调用这个方法。
                }
                if (compareAndSetState(state, state - arg)) {
                    return 1; //获取锁成功
                }
            }
        }

        @Override
        protected boolean tryReleaseShared(int arg) {
            for (;;) {
                int state = getState();
                if (compareAndSetState(state, state + arg)) {
                    return true;
                }
            }
        }

        public Condition newCondition() {
            return new ConditionObject();
        }
    }
}
